package com.zxcl.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zxcl.domain.ProdPropValue;
import com.zxcl.dto.PageDTO;
import com.zxcl.dto.PropAddDTO;
import com.zxcl.dto.PropQueryDTO;
import com.zxcl.dto.PropUpdateDTO;
import com.zxcl.ex.BusinessException;
import com.zxcl.mapper.ProdPropValueMapper;
import com.zxcl.utils.AuthUtil;
import com.zxcl.vo.ProdPropVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zxcl.mapper.ProdPropMapper;
import com.zxcl.domain.ProdProp;
import com.zxcl.service.impl.ProdPropService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

@Service
public class ProdPropServiceImpl extends ServiceImpl<ProdPropMapper, ProdProp> implements ProdPropService{

    @Autowired
    private ProdPropValueMapper prodPropValueMapper;

    /**
     * 分页查询规格和规格值
     *
     *  * 1.join
     *      * 2.查到规格集合  循环 查 对应的规格值的集合
     *      * 3.查到规格数据 拿到ids 查规格值的数据 在内存中做join
     *      这里采用的3，最高效
     * @param pageDTO
     * @param propQueryDTO
     * @return
     */
    @Override
    public Page<ProdPropVo> loadProdPropVoPage(PageDTO pageDTO, PropQueryDTO propQueryDTO) {
        ProdPropMapper prodPropMapper = getBaseMapper();
        //设置分页规格数据
        Page<ProdProp> page = new Page<>(pageDTO.getCurrent(), pageDTO.getSize());
        //返回的vo数据
        Page<ProdPropVo> propVoPage = new Page<>(pageDTO.getCurrent(), pageDTO.getSize());
        //关于不同的店铺shopId 有不同的规格
        //shopId为1说明时超级管理员，可以查询所有店铺的规格
        Long shopId = AuthUtil.getShopId();

        //从规格表中分页查询所有数据 封装到mybatis-plus的Page对象中
        Page<ProdProp> prodPropPage = prodPropMapper.selectPage(page, new LambdaQueryWrapper<ProdProp>()
                .eq(!shopId.equals(1L), ProdProp::getShopId, shopId) //如果 shopId 不等于 1L，则设置查询条件为匹配 ProdProp 对象的 shopId 字段与 shopId 变量的值相等。换句话说，根据给定的条件动态构建查询语句，以满足特定的查询需求。
                .like(StringUtils.hasText(propQueryDTO.getPropName()), ProdProp::getPropName, propQueryDTO.getPropName())
        );
        //从封装对象中取出查询到的所有数据
        List<ProdProp> prodPropList = prodPropPage.getRecords();
        if (CollectionUtils.isEmpty(prodPropList)){
            //如果是空的，就返回空的VO出去
            return propVoPage;
        }
        //取出这张表中的所有id
        Set<Long> prodPropIds = prodPropList.stream().map(ProdProp::getPropId).collect(Collectors.toSet());
        //
        if (!CollectionUtils.isEmpty(prodPropIds)){
            //根据id查询规格值表中的数据
            List<ProdPropValue> prodPropValues = prodPropValueMapper.selectList(new LambdaQueryWrapper<ProdPropValue>()
                    .in(ProdPropValue::getPropId, prodPropIds)
            );
            //内存中组装数据
            //80 （prodPropValues（32G,64G,128G））
            List<ProdPropVo> prodPropVos = new ArrayList<>(prodPropList.size());
            //prodPropValues  111(1) 112(1)    113(2) 114(2)       115(3)  116(3)
            Map<Long, List<ProdPropValue>> prodPropMap = prodPropValues.stream().collect(Collectors.groupingBy(ProdPropValue::getPropId));
            //循环
            prodPropList.forEach(prodProp -> {
                ProdPropVo prodPropVo = new ProdPropVo();
                BeanUtils.copyProperties(prodProp,prodPropVo);
                prodPropVo.setProdPropValues(prodPropMap.get(prodPropVo.getPropId()));
                prodPropVos.add(prodPropVo);
            });
            propVoPage.setRecords(prodPropVos);
            propVoPage.setTotal(prodPropPage.getTotal());
            propVoPage.setPages(prodPropPage.getPages());
        }

        return propVoPage;
    }

    /**
     * 新增规格和规格值
     * @param propAddDTO
     * @param shopId
     * @return
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class) //回滚是报运行时异常
    public Integer addPropAndVals(PropAddDTO propAddDTO, Long shopId) {
        String propName = propAddDTO.getPropName();
        //查询属性名称和商铺id为给定值的总数
        Long count = getBaseMapper().selectCount(new LambdaQueryWrapper<ProdProp>()
                .eq(ProdProp::getPropName, propName)
                .eq(ProdProp::getPropId, shopId)
        );
        if (count>0){
            throw new BusinessException("["+propName+"]的规格属性已存在");
        }

        ProdProp prodProp = new ProdProp();
        prodProp.setPropName(propName);
        prodProp.setRule(1);
        prodProp.setShopId(shopId);

        //保存规格到规格表中,propId没写会自增
        int row = getBaseMapper().insert(prodProp);
        Long propId = prodProp.getPropId();
        if (row>0){

            List<ProdPropValue> prodPropValues = propAddDTO.getProdPropValues();
            if (!CollectionUtils.isEmpty(prodPropValues)){
                prodPropValues.forEach(prodPropValue -> {
                    prodPropValue.setPropId(propId);
                    //保存到规格值表中
                    prodPropValueMapper.insert(prodPropValue);
                });
            }

        }
        return row;
    }

    /**
     * 修改规格和规格值
     * @param propUpdateDTO
     * TODO 需要优化
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class) //回滚是报运行时异常
    public Integer updatePropAndVals(PropUpdateDTO propUpdateDTO) {
        //获取规格数据id
        Long propId = propUpdateDTO.getPropId();

        //根据规格表id修改对应的数据
        int update = getBaseMapper().update(propUpdateDTO );

        if (update != 1){
            throw new BusinessException("服务器异常.....");
        }

        //获取需要修改的规格值表数据
        List<ProdPropValue> prodPropValues = propUpdateDTO.getProdPropValues();

        //根据规格表id查询对应的规格值表数据
        List<ProdPropValue> propValueList = prodPropValueMapper.selectList(new LambdaQueryWrapper<ProdPropValue>()
                .eq(ProdPropValue::getPropId, propId));
        //判断传入规格值表长度与查询的长度进行比较，判断到底是删除还是修改还是新增

        if (prodPropValues.size() == propValueList.size()){
            //代表需要进行修改
            //还有一种可能先删除在添加再修改一起操作的时候
            int delete = prodPropValueMapper.delete(new LambdaQueryWrapper<ProdPropValue>().eq(ProdPropValue::getPropId, propId));
            if (delete <= 0){
                //删除规格表id对应的所有规格值表数据
                throw new BusinessException("服务器异常.....");
            }
            prodPropValues.forEach(prodPropValue -> {
                //删除规格表id对应的所有规格值表数据
                if (prodPropValue.getPropId() == null){
                    //代表新增
                    prodPropValue.setPropId(propId);
                    int insert = prodPropValueMapper.insert(prodPropValue);
                    if (insert != 1){
                        throw new BusinessException("服务器异常.....");
                    }
                }else {
                    int insert = prodPropValueMapper.insert(prodPropValue);
                    if (insert != 1){
                        throw new BusinessException("服务器异常.....");
                    }
                }
            });
        }else if (prodPropValues.size() < propValueList.size()){
            //代表需要删除
            int delete = prodPropValueMapper.delete(new LambdaQueryWrapper<ProdPropValue>().eq(ProdPropValue::getPropId, propId));
            if (delete <= 0){
                //删除规格表id对应的所有规格值表数据
                throw new BusinessException("服务器异常.....");
            }
            //添加
            prodPropValues.forEach(prodPropValue -> {
                int insert = prodPropValueMapper.insert(prodPropValue);
                if (insert != 1){
                    throw new BusinessException("服务器异常.....");
                }
            });
        } else {
            //代表需要新增，随便进行已有规格值表修改
            prodPropValues.forEach(prodPropValue -> {
                if (prodPropValue.getPropId() == null){
                    //需要添加
                    prodPropValue.setPropId(propId);
                    int insert = prodPropValueMapper.insert(prodPropValue);
                    if (insert != 1){
                        throw new BusinessException("服务器异常.....");
                    }
                }else {
                    //修改
                    int i = prodPropValueMapper.updateById(prodPropValue);
                    if (i != 1){
                        throw new BusinessException("服务器异常.....");
                    }
                }
            });
        }
        return update;
    }

    /**
     * 查询规格列表
     * @param shopId
     * @return
     */
    @Override
    public List<ProdProp> loadProdProps(Long shopId) {
        return getBaseMapper().selectList(new LambdaQueryWrapper<ProdProp>()
                .eq(ProdProp::getShopId,shopId)
        );
    }

    /**
     * 根据规格id查询规格值列表
     *
     * @param propId
     * @return
     */
    @Override
    public List<ProdPropValue> loadPropVals(Long propId) {
        return prodPropValueMapper.selectList(new LambdaQueryWrapper<ProdPropValue>()
                .eq(ProdPropValue::getPropId, propId)
        );
    }


}
